{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Balun & Transformer Designs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import skrf as rf\n",
    "\n",
    "rf.stylely()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial explains a few passive RF circuits, such as ferrite-loaded baluns & transformers using transmission lines, within the scikit-rf environment.  We tested these circuits in Windows Anaconda, Android Pydroid 3 and iOS Juno.\n",
    "\n",
    "## Balun\n",
    "\n",
    "Baluns are balanced-to-unbalanced circuits. In other words, baluns convert differential to single-ended circuits, and vice versa.\n",
    "\n",
    "Transformers, as the name indicates, transform one RF impedance to another.\n",
    "\n",
    "Both baluns and transformers can be built using transmission lines or lumped elements. Baluns and transformers are used extensively, but not exclusively, in RF matching circuits, combiners, dividers, amplifiers, mixers. At times, baluns and transformers are used in antenna designs, antenna emulators and/or antenna tuners (aka couplers).\n",
    "\n",
    "<img src=\"Balun_Transformer_Designs/Simple_Balun2.png\"/>\n",
    "\n",
    "Fig.1 Ideal Schematic of a Coax Balun\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Fig.1 above, a coaxial balun is depicted and is comprised of a 4-port (outer conductor floating) coax and a resistor. In this circuit, the resistor is employed to model the effect of a ferrite sleeve (or bead) around the coax. The resistor acts to discourage current flow on the outside surface of the outer conductor, which makes the coax behave exactly like a twisted pair of wires over a bandwidth of interest. In some cases, a lumped inductor can replace the resistor to model the frequency-dependent behavior of the ferrite material of the sleeve. The actual value of the resistor, or the inductor, is a function of the frequency range of the design and the characteristics of the ferrite material. Often, the value of the resistor, or inductor, is derived from experimental measurements in the lab. We use 333-Ohms here as a reasonable value to demonstrate the usage of scikit-rf only.\n",
    "\n",
    "In reality, a 4-port transmission line is implemented in scikit-rf exactly as shown in the nodal diagram of figure below:\n",
    "\n",
    "<img src=\"Balun_Transformer_Designs/Nodal_Connections_Simple_Balun.png\" />\n",
    "\n",
    "Fig.2 Nodal Connections"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using Fig.2 as a guide, we can create a transmission-line balun as follows. First, we add some insertion loss to the trandmission lines in the firm of a 0.1-Ohm resistor.  Then we connect all the elements (transformer, two 25-Ohms lines and the ferrite resistor) together to create the balun.  The sum port is 50-Ohms single-ended.  The differential output ports are 25-Ohms each."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# need this ideal s4p file to create a coax with a floating outer conductor\n",
    "xformer = r\"Balun_Transformer_Designs/Ideal_4port_xformer_hi_res.s4p\"\n",
    "xformer_ntwk = rf.Network(xformer)\n",
    "xformer_ntwk1 = xformer_ntwk[\"0.001-2ghz\"]  # band center is thus 1 GHz\n",
    "\n",
    "freq = xformer_ntwk1.frequency\n",
    "z0_ports = 25\n",
    "\n",
    "beta = freq.w / rf.c\n",
    "line_branch = rf.media.DefinedGammaZ0(frequency=freq, z0=z0_ports, gamma=0+beta*1j)\n",
    "\n",
    "# d is 75 mm in length, which is quarterwave at 1 GHz in air\n",
    "#d = line_branch.theta_2_d(90, deg=True, bc=True)\n",
    "branch1 = line_branch.line(90, unit=\"deg\", name=\"branch1\")\n",
    "\n",
    "lossy_line = line_branch.resistor(0.1, name=\"res\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The RF circuit is build using the scikit-rf [Circuit](https://scikit-rf.readthedocs.io/en/latest/tutorials/Circuit.html) capabilities:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "port1 = rf.Circuit.Port(freq, name=\"port1\", z0=25)\n",
    "port2 = rf.Circuit.Port(freq, name=\"port2\", z0=25)\n",
    "\n",
    "# creating a 25-Ohm 2-port transmission line, with realistic insertion loss\n",
    "# insertion loss is equivalent to a 0.1-Ohm series resistor\n",
    "connections = [\n",
    "    [(port1, 0), (lossy_line, 0)],\n",
    "    [(lossy_line, 1), (branch1, 0)],\n",
    "    [(branch1, 1), (port2, 0)],\n",
    "]\n",
    "\n",
    "C = rf.Circuit(connections)\n",
    "\n",
    "line1 = C.network\n",
    "line1.name = \"top line\"\n",
    "line2 = C.network\n",
    "line2.name = \"bottom line\"\n",
    "\n",
    "line = rf.media.DefinedGammaZ0(frequency=freq, z0=50)\n",
    "ferrite_resistor = line.resistor(333, name=\"res\")\n",
    "\n",
    "port1a = rf.Circuit.Port(frequency=freq, name=\"port1a\", z0=50)\n",
    "port2a = rf.Circuit.Port(frequency=freq, name=\"port2a\", z0=25)\n",
    "port3a = rf.Circuit.Port(frequency=freq, name=\"port3a\", z0=25)\n",
    "ground = rf.Circuit.Ground(frequency=freq, name=\"ground\", z0=50)\n",
    "\n",
    "# creating a 4-port floating coax by feeding two 25-Ohm lines (twisted pair of wires)\n",
    "# with an ideal transformer, to ensure the differential nature of the twisted pair, as per Fig.2\n",
    "# the 333-Ohm resistor models the loading of the ferrite sleeve,\n",
    "# upon the outer conductor of the 4-port coax line\n",
    "conn = [\n",
    "    [(port1a, 0), (xformer_ntwk1, 0)],\n",
    "    [(xformer_ntwk1, 1), (line1, 0)],\n",
    "    [(line1, 1), (port2a, 0)],\n",
    "    [(ground, 0), (xformer_ntwk1, 2), (ferrite_resistor, 0)],\n",
    "    [(xformer_ntwk1, 3), (line2, 0)],\n",
    "    [(line2, 1), (ferrite_resistor, 1), (port3a, 0)],\n",
    "]\n",
    "\n",
    "C1 = rf.Circuit(conn)\n",
    "balun = C1.network\n",
    "balun.name = \"ideal balun\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's have a look the the S-parameters of this ideal balun:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)\n",
    "\n",
    "balun.plot_s_db(ax=ax1, m=0, n=0, lw=2)  # S11\n",
    "balun.plot_s_db(ax=ax1, m=1, n=1, lw=2)  # S22\n",
    "ax1.set_ylim(-60, 0)\n",
    "\n",
    "balun.plot_s_db(ax=ax2, m=1, n=0, lw=2)  # S21\n",
    "ax2.set_ylim(-4, 0)\n",
    "\n",
    "fig.suptitle(\"Ideal 50-Ohm balun\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As can be seen from graph above, the sum port return loss S11 (blue trace, upper graph) is -35dB.  The S22 (red trace, upper graph) is -6dB, indicating the typical return loss of a terminal within a differential pair.  The S21 (blue trace, lower graph) is -3dB, as expected, to show that the energy entering the sum port splits evenly between the two differential ports.\n",
    "\n",
    "The above example of a balun design was implemented in scikit-rf version 1.3 (also compatible with earlier versions).  For scikit-rf version 1.4, the script below employs a newly created Media element, called [line_floating](https://scikit-rf.readthedocs.io/en/latest/api/media/generated/skrf.media.Media.line_floating.html#skrf.media.Media.line_floating), to simplify the circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "freq1 = rf.Frequency(start=0.01, stop=2, unit=('GHz'), npoints=2001)\n",
    "beta = freq1.w / rf.c\n",
    "\n",
    "line1 = rf.media.DefinedGammaZ0(frequency=freq1, z0=50, gamma=0+beta*1j)\n",
    "\n",
    "ferrite_resistor = line1.resistor(333, name='res') # model ferrite sleeve as a parallel 333 Ohm resistor\n",
    "Rp_circuit = ferrite_resistor\n",
    "\n",
    "# define a floating 4-port transmission line, using a new element in ver 1.4 of Scikit-rf\n",
    "line4p = line1.line_floating(90, unit='deg', z0=50, name='line4p')\n",
    "port1 = rf.Circuit.Port(frequency=freq1, name='port1', z0=50)\n",
    "port2 = rf.Circuit.Port(frequency=freq1, name='port2', z0=25)\n",
    "port3 = rf.Circuit.Port(frequency=freq1, name='port3', z0=25)\n",
    "ground = rf.Circuit.Ground(frequency=freq1, name='ground', z0=50)\n",
    "\n",
    "connections = [[(port1, 0), (line4p, 0)],\n",
    "    [(port2, 0), (line4p, 1)],\n",
    "    [(port3, 0), (line4p, 3), (Rp_circuit, 0)],\n",
    "    [(line4p, 2), (Rp_circuit, 1), (ground, 0)]]\n",
    "\n",
    "circuit = rf.Circuit(connections)\n",
    "balun_circuit = circuit.network\n",
    "balun_circuit.name = 'ideal balun circuit'\n",
    "\n",
    "fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)\n",
    "\n",
    "balun_circuit.plot_s_db(ax=ax1, m=0, n=0, lw=2)  # S11\n",
    "balun_circuit.plot_s_db(ax=ax1, m=1, n=1, lw=2)  # S22\n",
    "ax1.set_ylim(-60, 0)\n",
    "\n",
    "balun_circuit.plot_s_db(ax=ax2, m=1, n=0, lw=2)  # S21\n",
    "ax2.set_ylim(-4, 0)\n",
    "\n",
    "fig.suptitle(\"Ideal 50-Ohm balun\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Guanella transformer\n",
    "The next circuit to be explored is a Guanella transformer, which is a 4-to-1 impedance transformer. In this example, a 100-Ohms impedance is transformed to 25-Ohms using two 50-Ohms transmission lines. This example is implemented in scikit-rf version 1.4.\n",
    "<img src=\"Balun_Transformer_Designs/Guanella_transformer_1.png\"/>\n",
    "\n",
    "Fig.3 Ideal Guanella Transformer\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using Fig.3 as a nodal guide, a Guanella transformer can be created.  Note that on the left-hand side of the circuit, the two transmission lines are connected in RF series to form the 100-Ohms port.  On the opposite end, the right-hand side is connected in parallel to form the 25-Ohms port.  Also, the ferrite sleeve is modeled as an inductor in this example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "freq = rf.Frequency(start=0.01, stop=2, unit=('GHz'), npoints=2001)\n",
    "beta = freq.w/rf.c\n",
    "\n",
    "line = rf.media.DefinedGammaZ0(frequency=freq, z0=50, gamma=0+beta*1j)\n",
    "ferrite_inductor = line.inductor(100e-9, name='ind') # model ferrite sleeve as a parallel 100 nH inductor\n",
    "\n",
    "# define a floating 4-port transmission line\n",
    "line4p_a = line.line_floating(90, unit='deg', z0=50, name='line4p_a')\n",
    "line4p_b = line.line_floating(90, unit='deg', z0=50, name='line4p_b')\n",
    "\n",
    "port1 = rf.Circuit.Port(frequency=freq, name='port1', z0=100)\n",
    "port2 = rf.Circuit.Port(frequency=freq, name='port2', z0=25)\n",
    "ground1 = rf.Circuit.Ground(frequency=freq, name='ground1', z0=50)\n",
    "ground2 = rf.Circuit.Ground(frequency=freq, name='ground2', z0=50)\n",
    "\n",
    "connections = [[(port1, 0), (line4p_a, 0)],\n",
    "    [(port2, 0), (line4p_a, 1), (line4p_b, 1)],\n",
    "    [(line4p_a, 2), (line4p_b, 0), (ferrite_inductor, 0)],\n",
    "    [(line4p_a, 3), (ferrite_inductor, 1), (ground1, 0), (line4p_b, 3)],\n",
    "    [(line4p_b, 2), (ground2, 0)]]\n",
    "\n",
    "circuit = rf.Circuit(connections)\n",
    "transf_circuit = circuit.network\n",
    "transf_circuit.name = 'ideal Guanella transformer circuit'\n",
    "\n",
    "transf_circuit.plot_s_db(m=0, n=0, lw=2)\n",
    "transf_circuit.plot_s_db(m=1, n=0, lw=2)\n",
    "transf_circuit.plot_s_db(m=1, n=1, lw=2)\n",
    "\n",
    "plt.ylim(-50,10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this Guanella transformer example, the ferrite sleeve is modeled as an inductor shunting across the outer conductor of the upper coax.  As can be seen in the S-parameter plot immediately above, the transformer works well between 200 and 1000 MHz.  Below 200 MHz, the ferrite-sleeve inductor does not provide enough impedance to \"choke\" to coax line properly.  At 1000 MHz, this circuit has a sharp resonance which constrains the upper frequency limit to 1 GHz."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Marchand balun\n",
    "The final circuit that we discuss here is the triax [Marchand balun](https://www.microwaves101.com/encyclopedias/marchand-balun), which does not employ any ferrite material.  In this circuit, two triax sections are cascaded and the balanced output is taken from the middle. Fig.4 shows a sketch of a Marchand balun, as per the description in the original Marchand's paper.\n",
    "\n",
    "<img src=\"Balun_Transformer_Designs/Annotated_Marchand.png\" />\n",
    "\n",
    "Fig.4 Original Marchand Balun Drawing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As can be seen in Fig.4, the triax cross section has an inner conductor that is shielded by an intermediate circular outer conductor.  In turn, the circular outermost outer conductor envelopes the intermediate conductor.\n",
    "\n",
    "Fig.5 Shows an electrical circuit which models the triax Marchand balun.  Two nested coax lines are employed to emulate one triax structure.  \n",
    "\n",
    "<img src=\"Balun_Transformer_Designs/Marchand_Balun.png\"/>\n",
    "\n",
    "Fig.5 Ideal Marchand Balun Circuit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As seen in Fig.5, coax CX1 and CX2 form the first triax.  The inner most coax impedance CX1 is 50-Ohms.  The outer conductor of CX1 becomes the inner conductor of the 120-Ohms CX2.\n",
    "\n",
    "The second triax is formed by the 10-Ohms CX3 and the 120-Ohms CX4.  Similar to the previous triax, the outer conductor of CX3 becomes the inner conductor of CX4.\n",
    "\n",
    "The ideal transformer in Fig.5 is needed to show that the output of the Marchand balun is indeed differential."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ideal transformer to convert differential ports to 50-Ohms single-ended\n",
    "xformer = r\"Balun_Transformer_Designs/Ideal_4port_xformer_hi_res.s4p\"\n",
    "xformer_ntwk = rf.Network(xformer)\n",
    "xformer_ntwk1a = xformer_ntwk[\"0.001-2ghz\"]\n",
    "\n",
    "freq = xformer_ntwk1a.frequency\n",
    "beta = freq.w/rf.c\n",
    "\n",
    "line = rf.media.DefinedGammaZ0(frequency=freq, z0=50, gamma=0+beta*1j)\n",
    "C1 = line.capacitor(0.106e-12, name='cap')\n",
    "\n",
    "# define a floating 4-port transmission line\n",
    "line4p_a1 = line.line_floating(90, unit='deg', z0=50, name='line4p_a1')\n",
    "line4p_b1 = line.line_floating(90, unit='deg', z0=120, name='line4p_b1')\n",
    "line4p_c1 = line.line_floating(90, unit='deg', z0=10, name='line4p_c1')\n",
    "line4p_d1 = line.line_floating(90, unit='deg', z0=120, name='line4p_d1')\n",
    "\n",
    "port1a = rf.Circuit.Port(frequency=freq, name='port1', z0=50)\n",
    "port2a = rf.Circuit.Port(frequency=freq, name='port2', z0=50)\n",
    "ground1a = rf.Circuit.Ground(frequency=freq, name='ground1', z0=50)\n",
    "ground2a = rf.Circuit.Ground(frequency=freq, name='ground2', z0=50)\n",
    "\n",
    "connections = [[(port1a, 0), (line4p_a1, 0)],\n",
    "    [(ground1a, 0), (line4p_a1, 2), (line4p_b1, 0), (line4p_b1, 2), (line4p_b1, 3)],\n",
    "    [(line4p_a1, 1), (line4p_c1, 0)],\n",
    "    [(line4p_a1, 3), (line4p_b1, 1), (xformer_ntwk1a, 0)],\n",
    "    [(line4p_c1, 2), (xformer_ntwk1a, 2), (line4p_d1, 0)],\n",
    "    [(line4p_d1, 1), (line4p_c1, 3), (line4p_d1, 2), (line4p_d1, 3), (C1, 1), (xformer_ntwk1a, 3), (ground2a, 0)],\n",
    "    [(line4p_c1, 1), (C1, 0)],\n",
    "    [(xformer_ntwk1a, 1), (port2a, 0)]]\n",
    "\n",
    "circuit1 = rf.Circuit(connections)\n",
    "Marchand_circuit = circuit1.network\n",
    "Marchand_circuit.name = 'Marchand circuit'\n",
    "\n",
    "Marchand_circuit.plot_s_db(m=0, n=0, lw=2)\n",
    "Marchand_circuit.plot_s_db(m=1, n=0, lw=2)\n",
    "Marchand_circuit.plot_s_db(m=1, n=1, lw=2)\n",
    "\n",
    "plt.ylim(-50,10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the S-parameter plot of the Marchand balun above, the bandwidth of this circuit is from 250 to 1600 MHz (-20dB return-loss bandwidth).  This multi-octave performance is achieved without the use of any ferrite sleeve.  The compromise here is the complexity of the balun's construction.\n",
    "\n",
    "Using these three simple examples, one can build many other interesting transmission-line circuits in scikit-rf.  Furthermore, these circuits can be built on an iphone (Juno), or an Android tablet (Pydroid 3), or a laptop (Anaconda).  Such ease of access allows design ideas to be quickly & accurately captured and tested where or whenever they are conceived. The possibilities and potentials are endless."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
